home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / What's New? / Development Kits / Mac OS / USB DDK 1.4.6f4 / Examples / PrinterClassDriver / PrintChooserSample / Chooser.cp next >
Encoding:
Text File  |  2000-09-25  |  32.6 KB  |  1,145 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Chooser.cp
  3.  
  4.     Contains:    Chooser PACK code to support USB and serial printers
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.  
  9.  
  10.     Copyright:    © 1998, 2000 by Apple Computer, Inc., all rights reserved.
  11.  
  12. */
  13.  
  14. #ifndef __Chooser__
  15. #include "Chooser.h"
  16. #endif
  17.  
  18. #ifndef __COMMON__
  19. #include "Common.h"
  20. #endif
  21.  
  22. #ifndef __UTILS__
  23. #include "Utils.h"
  24. #endif
  25.  
  26. #ifndef __DEVICES__
  27. #include <Devices.h>
  28. #endif
  29.  
  30. #ifndef __RESOURCES__
  31. #include <Resources.h>
  32. #endif
  33.  
  34. #ifndef __TEXTUTILS__
  35. #include <TextUtils.h>
  36. #endif
  37.  
  38. #ifndef __COMMRESOURCES__
  39. #include <CommResources.h>
  40. #endif
  41.  
  42. #ifndef __CRMSERIALDEVICES__
  43. #include <CRMSerialDevices.h>
  44. #endif
  45.  
  46. #ifndef __MIXEDMODE__
  47. #include <MixedMode.h>
  48. #endif
  49.  
  50. #ifndef __CODEFRAGMENTS__
  51. #include <CodeFragments.h>
  52. #endif
  53.  
  54. #ifndef __DIALOGS__
  55. #include <dialogs.h>
  56. #endif
  57.  
  58. #ifndef __SafeNameRegistry__
  59. #include "SafeNameRegistry.h"
  60. #endif
  61.  
  62. /******************************************************************************
  63.     Typedefs
  64.  ******************************************************************************/
  65.  
  66. // This structure is passed to AddPrintertoList (a callback routine) from
  67. // SearchForUSBPrinters. Its used to hold data which is needed to add a
  68. // printer name to the Chooser's printer list
  69. typedef struct
  70. {
  71.     ListHandle    list;            // the printer list
  72.     Cell        insertcell;        // where to insert an entry
  73.     short        modelIndex;        // index into STR# holding printer models supported
  74. } AddPrintertoListCallBackStruct, *AddPrintertoListCallBackStructPtr;
  75.  
  76. // This structure is passed to AddPorttoList (a callback routine) from
  77. // SearchForSerialPorts. Its used to hold data which is needed to add a
  78. // serial port to the Chooser's printer list
  79. typedef struct
  80. {
  81.     ListHandle    list;            // the printer list
  82.     Cell        insertcell;        // where to insert an entry
  83. } AddPorttoListCallBackStruct, *AddPorttoListCallBackStructPtr;
  84.  
  85. // typedef for callback routine used in SearchForUSBPrinters when a printer
  86. // entry is found in the name registry
  87. typedef void (*FoundUSBPrinterProcPtr) ( RegEntryID* aPrinterEntry, void* userData);
  88.  
  89. // typedef for callback routine used in SearchForSerialPorts when a port
  90. // entry is found in the name registry
  91. typedef void (*FoundSerialPortProcPtr) ( CRMSerialPtr aPort, void* userData);
  92.  
  93. /******************************************************************************
  94.     Prototypes
  95.  ******************************************************************************/
  96.  
  97. short    CountUSBPrinters(void);
  98. void    FillPrinterList( ListHandle list );
  99. void    AddPrintertoList( RegEntryID* aPrinterEntry, void* userData );
  100. void    CountAPrinter( RegEntryID* aPrinterEntry, void* userData );
  101. void    SearchForUSBPrinters( StringPtr modelPath, FoundUSBPrinterProcPtr callback, void* userData );
  102.  
  103. short    CountSerialPorts(void);
  104. void    AddPorttoList( CRMSerialPtr aPort, void* userData );
  105. void    CountAPort(  CRMSerialPtr aPort, void* userData );
  106. void    SearchForSerialPorts(FoundSerialPortProcPtr callback, void* userData);
  107.  
  108. OSErr    ShowSelection (ListHandle list, StringPtr zoneName);
  109. OSErr    Select (ListHandle list, StringPtr zoneName, long rowNum);
  110.  
  111. void    SetConnectionType(short    type);
  112. short    GetConnectionType(void);
  113. OSErr    InitPack(void);
  114.  
  115. Boolean    SaveSelectedUSBPrinter( Cell selectedCell, ListHandle list );
  116. void    SaveSelectedPrinterName( Cell selectedCell, ListHandle list);
  117. Handle    GetLastSelectedUSBPrinter();
  118.  
  119. /******************************************************************************
  120.     Constants
  121.  ******************************************************************************/
  122.  
  123. #define        kHilited    0
  124. #define        kUnHilited    255
  125.  
  126. #define        kGlobalType        'wxyz'        // made up type
  127. #define        kGlobalID        128
  128.  
  129. #define        kConnectionType        'CTYP'
  130. #define        kConnectionTypeID    1000
  131.  
  132. // Possible selected types. Used in ConnectionType rsrc
  133. #define        kNone            0
  134. #define        kSerial            1
  135. #define        kUSB            2
  136.  
  137. #define     kAPortName    "\p.AIn"    // To compare input device name when searching serial devices in the Comm Tool Box's List
  138. #define        kBPortName    "\p.BIn"    // To comapre input device name when searching serial devices in the Comm Tool Box's List
  139.  
  140. #define        kPrinterNotAvailable    3100
  141. /*-----------------------------------------------------------------------------*
  142.  
  143.     SaveSelectedUSBPrinter
  144.     
  145.     Desc:        Saves the name registry path of the selected printer
  146.  
  147.     In:            - the cell of the selected printer
  148.                 - the Chooser's printer list
  149.                 - the row of the selected cell
  150.                 
  151.     Out:        true if the path was saved
  152.                 false if the path wasn't saved
  153.  
  154.     History:
  155.     
  156.     21 Apr 98    gp        Created
  157.     
  158.  *-----------------------------------------------------------------------------*/
  159. Boolean    SaveSelectedUSBPrinter( Cell selectedCell, ListHandle list )
  160. {
  161.     Handle        lastPrinterString=nil;    // the previous selected printer 
  162.     Str255         selectedPrinterName;    // name of the selected printer
  163.     Str255        modelString;    // path in name registry of printer model
  164.     Boolean        saved=false;            // was the selected printer saved properly
  165.  
  166.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  167.  
  168.     gGlobals = GetGlobalStorage();
  169.  
  170.     // Get the name of the printer that was selected out of the list
  171.     GetNameFromCell (selectedPrinterName, selectedCell, list);
  172.     // get the last selected printer
  173.     lastPrinterString = GetLastSelectedUSBPrinter();
  174.  
  175.     // get the model path
  176.     GetIndString(modelString, kUSBModelPathString, *((**gGlobals).modelIndex+selectedCell.v) );
  177.     if( modelString[0] != 0 && lastPrinterString != nil) 
  178.     {                
  179.         Handle    tempHandle=nil;
  180.         // create the selected printer's name registry path
  181.         AppendPStr( (StringPtr) modelString, "\p:" );
  182.         AppendPStr( (StringPtr) modelString, selectedPrinterName );
  183.         
  184.         HLock( lastPrinterString );
  185.         BlockMoveData( modelString, *lastPrinterString, modelString[0]+1 );
  186.         HUnlock( lastPrinterString );
  187.  
  188.         // save the selected printers's name registry path
  189.         ChangedResource( lastPrinterString );
  190.         SetConnectionType( kUSB );
  191.         
  192.         WriteResource(lastPrinterString);
  193.         saved = true;
  194.     }
  195.     return saved;
  196. }
  197.  
  198. /*-----------------------------------------------------------------------------*
  199.  
  200.     GetLastSelectedUSBPrinter
  201.     
  202.     Desc:        Returns the name registry path of the last selected USB printer
  203.  
  204.     In:            None
  205.                 
  206.     Out:        Handle to a STR containing the name registry path of the last
  207.                 selected USB printer
  208.  
  209.     History:
  210.     
  211.     21 Apr 98    gp        Created
  212.     
  213.  *-----------------------------------------------------------------------------*/
  214. Handle    GetLastSelectedUSBPrinter()
  215. {
  216.     Handle            printerString=nil;    // the full path in name registry of last selected USB printer
  217.  
  218.     printerString = Get1Resource( 'STR ', kUSBPrinterPathString );
  219.     if( printerString == nil ) {
  220.         DebugStr("\pIn GetLastSelectedUSBPrinter. THIS SHOULD NEVER HAPPEN");
  221.     }
  222.     return printerString;
  223. }
  224.  
  225. /*-----------------------------------------------------------------------------*
  226.  
  227.     SaveSelectedPrinterName
  228.     
  229.     Desc:        Saves the name of the selected printer in our rsrc
  230.  
  231.     In:            - the cell of the selected printer
  232.                 - the Choosers printer list handle
  233.                 
  234.     Out:        None
  235.  
  236.     History:
  237.     
  238.     21 Apr 98    gp        Created
  239.     
  240.  *-----------------------------------------------------------------------------*/
  241. void    SaveSelectedPrinterName( Cell selectedCell, ListHandle list)
  242. {
  243.     Handle            printerString=nil;        // path in name registry of current USB printer
  244.     Str255             selectedPrinterName;            // name of the selected printer
  245.  
  246.     GetNameFromCell (selectedPrinterName, selectedCell, list);
  247.  
  248.     // save the name of the printer
  249.     printerString = (Handle) Get1Resource( 'STR ', kPrinterNameString );
  250.     if( selectedPrinterName[0] != 0 && printerString != nil) 
  251.     {
  252.         HLock( printerString );
  253.         BlockMoveData( selectedPrinterName, *printerString, selectedPrinterName[0]+1 );
  254.         HUnlock( printerString );
  255.  
  256.         // save the newly selected printer's name
  257.         ChangedResource( printerString );
  258.         WriteResource(printerString);
  259.     }
  260.  
  261. }
  262.  
  263. /*-----------------------------------------------------------------------------*
  264.  
  265.     GetConnectionType
  266.     
  267.     Desc:        Gets the connection type for the last selected printer
  268.                 from our rsrc
  269.  
  270.     In:            None
  271.                 
  272.     Out:        kNone, kSerial or kUSB
  273.  
  274.     History:
  275.     
  276.     27 Mar 98    gp        Created
  277.     
  278.  *-----------------------------------------------------------------------------*/
  279. short    GetConnectionType(void)
  280. {
  281.     Handle    connection;
  282.  
  283.     connection = (Handle) Get1Resource( kConnectionType, kConnectionTypeID );
  284.     return (**(short**)connection);
  285.  
  286. }
  287.  
  288. /*-----------------------------------------------------------------------------*
  289.  
  290.     SetConnectionType
  291.     
  292.     Desc:        Saves the connection type of the selected printer in our rsrc
  293.  
  294.     In:            kNone, kSerial or kUSB
  295.                 
  296.     Out:        None
  297.     
  298.     History:
  299.     
  300.     27 Mar 98    gp        Created
  301.     
  302.  *-----------------------------------------------------------------------------*/
  303. void    SetConnectionType(short    type)
  304. {
  305.     Handle    connection;
  306.  
  307.     connection = (Handle) Get1Resource( kConnectionType, kConnectionTypeID );
  308.     (**(short**)connection) = type;
  309.     ChangedResource( connection );
  310.     WriteResource( connection );
  311. }
  312.  
  313. /*-----------------------------------------------------------------------------*
  314.  
  315.     CountAPort
  316.     
  317.     Desc:        Callback routine for CountSerialPorts. It increments the
  318.                 ptr to user data thus incrementing the count of serial ports.
  319.  
  320.     In:            - A port to a CRMSerialPtr struct
  321.                 - A ptr to user data
  322.  
  323.     Out:        None
  324.     
  325.     History:
  326.     
  327.     26 Mar 98    gp        Created
  328.     
  329.  *-----------------------------------------------------------------------------*/
  330. void    CountAPort(  CRMSerialPtr aPort, void* userData )
  331. {
  332.     // we're only interested in .ain and .bin
  333.     if ( (PStrEqualCaseInsensitive((unsigned char*) kBPortName, *(aPort->inputDriverName)) ) ||
  334.         (PStrEqualCaseInsensitive((unsigned char*) kAPortName, *(aPort->inputDriverName)) ))
  335.     {
  336.             *((short*) userData) +=1;
  337.     }
  338. }
  339.  
  340. /*-----------------------------------------------------------------------------*
  341.  
  342.     AddPorttoList
  343.     
  344.     Desc:        Adds a serial port the the Chooser's list. We're only interested
  345.                 in modem and printer ports
  346.  
  347.     In:            - A port to a CRMSerialPtr struct
  348.                 - A ptr to user data. This should be a ptr to a 
  349.                   AddPorttoListCallBackStruct
  350.  
  351.     Out:        None
  352.     
  353.     History:
  354.     
  355.     26 Mar 98    gp        Created
  356.     
  357.  *-----------------------------------------------------------------------------*/
  358. void    AddPorttoList( CRMSerialPtr aPort, void* userData )
  359. {
  360.     AddPorttoListCallBackStructPtr     addPortStruct=(AddPorttoListCallBackStructPtr) userData;
  361.  
  362.     // we're only interested in .ain and .bin
  363.     if ( PStrEqualCaseInsensitive((unsigned char*) kBPortName, *(aPort->inputDriverName)) )
  364.     {
  365.         LAddRow(1, addPortStruct->insertcell.v, addPortStruct->list);
  366.         LSetCell( "Printer", 7, addPortStruct->insertcell, addPortStruct->list );
  367.         addPortStruct->insertcell.v++;
  368.     }
  369.     
  370.     if ( PStrEqualCaseInsensitive((unsigned char*) kAPortName, *(aPort->inputDriverName)) )
  371.     {
  372.         LAddRow(1, addPortStruct->insertcell.v, addPortStruct->list);
  373.         LSetCell( "Modem", 5, addPortStruct->insertcell, addPortStruct->list );
  374.         addPortStruct->insertcell.v++;
  375.     }
  376. }
  377.  
  378. /*-----------------------------------------------------------------------------*
  379.  
  380.     CountSerialPorts
  381.     
  382.     Desc:        Returns the number of serial ports
  383.  
  384.     In:            None
  385.                 
  386.     Out:        The number of serial ports
  387.     
  388.     History:
  389.     
  390.     26 Mar 98    gp        Created
  391.     
  392.  *-----------------------------------------------------------------------------*/
  393. short    CountSerialPorts(void)
  394. {
  395.     short    numberOfPorts=0;
  396.  
  397.     SearchForSerialPorts( (FoundSerialPortProcPtr) &CountAPort, &numberOfPorts );
  398.  
  399.     return numberOfPorts;
  400. }
  401.  
  402. /*-----------------------------------------------------------------------------*
  403.  
  404.     SearchForSerialPorts
  405.     
  406.     Desc:        Searchs for serial ports on this machine
  407.  
  408.     In:            - A callback routine which gets called when a printer is found
  409.                 - A ptr to user data
  410.  
  411.     Out:        None
  412.     
  413.     History:
  414.     
  415.     26 Mar 98    gp        Created
  416.     
  417.  *-----------------------------------------------------------------------------*/
  418. void    SearchForSerialPorts(FoundSerialPortProcPtr callback, void* userData)
  419. {
  420.     CRMErr                theErr;                // comm rsrc manager error
  421.     CRMRec                commRec;            // communications resource manager record
  422.     CRMRecPtr            commRecPtr;            // ptr to a communication resource record in the queue
  423.     CRMSerialPtr        commRecSerialPtr;    // ptr to serial record inside comm resource record
  424.     long            curSerialDeviceID = 0;     // initially set to zero, so we get all serial devices
  425.  
  426.     theErr = InitCRM(); // Initialize the Communications Resource Manager
  427.  
  428.     // now search for serial devices
  429.     while (theErr == noErr)
  430.     {
  431.         commRec.crmDeviceType = crmSerialDevice; // look for serial devices
  432.         commRec.crmDeviceID = curSerialDeviceID; // look for a device number greater than curSerialDeviceID
  433.     
  434.         commRecPtr = &commRec;
  435.         commRecPtr = CRMSearch(commRecPtr);    // Search  queue for each serial device
  436.     
  437.         if (commRecPtr != nil)
  438.         {
  439.             // get the Serial record pointer
  440.             commRecSerialPtr = (CRMSerialPtr)(*commRecPtr).crmAttributes;
  441.             
  442.             callback( commRecSerialPtr, userData);    // found a port
  443.             
  444.             // Set device ID for next search
  445.             curSerialDeviceID = (*commRecPtr).crmDeviceID;
  446.         }
  447.         else
  448.         {
  449.             theErr = 1; // game over, no more serial devices
  450.         }
  451.     }
  452. }
  453.  
  454. /*-----------------------------------------------------------------------------*
  455.  
  456.     SearchForUSBPrinters
  457.     
  458.     Desc:        Searches thru a printer model entry in the name registry
  459.                 looking for a model's printers. When one is found a call is 
  460.                 issued to the clients callback routine for further processing
  461.  
  462.     In:            - A pstring full path in the name registry of a printer model
  463.                 - A callback routine which gets called when a printer is found
  464.                 - A ptr to user data
  465.                 
  466.     Out:        None
  467.     
  468.     History:
  469.     
  470.     24 Feb 98    gp        Created
  471.     
  472.  *-----------------------------------------------------------------------------*/
  473. void    SearchForUSBPrinters( StringPtr modelPath, FoundUSBPrinterProcPtr callback, void* userData )
  474. {
  475.  
  476.     RegEntryID        theModelEntry;        // the model node supported by the driver
  477.     RegEntryID        aPrinterEntry;        // a printer node in the name registry
  478.     RegEntryIterationOp iterOp;            // name registry iterator op code
  479.     RegEntryIter    printerIterator;    // used to iterate child nodes of printer model
  480.     Boolean            donePrinters    = false;    // NameRegistry param tell when we're done
  481.     OSStatus        err             = noErr;    // error from name registry calls
  482.  
  483.     // name registry only deals with c strings
  484.     p2cstr( (StringPtr) modelPath );
  485.  
  486.     // look up the node for the printer model requested
  487.     err = SafeRegistryEntryIDInit(&theModelEntry);
  488.     err = SafeRegistryCStrEntryLookup( nil, (char*) modelPath, &theModelEntry );
  489.  
  490.     if( err == noErr ) 
  491.     {
  492.         // create an iterator to look at the child nodes for our printer model entry
  493.         iterOp = kRegIterChildren;
  494.  
  495.         err = SafeRegistryEntryIterateCreate( &printerIterator );
  496.         err = SafeRegistryEntryIterateSet(&printerIterator, &theModelEntry);
  497.         
  498.         if( err == noErr )
  499.         {
  500.             // look for a model's connected printers
  501.             do
  502.             {
  503.                 err = SafeRegistryEntryIterate( &printerIterator, iterOp, &aPrinterEntry, &donePrinters );
  504.                 if( !donePrinters && err == noErr )
  505.                     callback(&aPrinterEntry, userData);    // found a printer
  506.  
  507.                 iterOp = kRegIterContinue;
  508.             } while( !donePrinters && err == noErr );
  509.             // end while for printers
  510.         }
  511.         SafeRegistryEntryIterateDispose(&printerIterator);
  512.     }
  513.  
  514.     SafeRegistryEntryIDDispose( &theModelEntry );
  515.     c2pstr( (char*) modelPath );
  516.  
  517. }
  518.  
  519. /*-----------------------------------------------------------------------------*
  520.  
  521.     CountAPrinter
  522.     
  523.     Desc:        Callback routine for CountUSBPrinters. It increments the
  524.                 ptr to user data thus incrementing the count of USB printers.
  525.  
  526.     In:            - A printer entry in the name registry
  527.                 - A ptr to user data
  528.                 
  529.     Out:        The number of USB printers in the name registry
  530.     
  531.     History:
  532.     
  533.     24 Feb 98    gp        Created
  534.     
  535.  *-----------------------------------------------------------------------------*/
  536.  
  537. void    CountAPrinter(  RegEntryID* aPrinterEntry, void* userData )
  538. {
  539.     *((short*) userData) +=1;
  540. }
  541.  
  542. /*-----------------------------------------------------------------------------*
  543.  
  544.     CountUSBPrinters
  545.     
  546.     Desc:        Returns the number of connected USB printers associated with this driver
  547.  
  548.     In:            None
  549.                 
  550.     Out:        The number of USB printers in the name registry
  551.     
  552.     History:
  553.     
  554.     24 Feb 98    gp        Created
  555.     
  556.  *-----------------------------------------------------------------------------*/
  557.  
  558. short    CountUSBPrinters()
  559. {
  560.     short            numberOfPrinters=0;    // return value for number of USB printers
  561.     Str255            modelPath;            // pstring path in a supported printer model
  562.     short            i;                    // counter
  563.  
  564.     i=1;
  565.     // read a supported printer's name registry model path
  566.     GetIndString(modelPath, kUSBModelPathString, i);
  567.     
  568.     while( (char*) modelPath[0] != 0 )        // if len is zero then no more models
  569.     {
  570.         SearchForUSBPrinters( modelPath, (FoundUSBPrinterProcPtr) &CountAPrinter, &numberOfPrinters );
  571.         i++;
  572.         // read another supported printer's name registry model path
  573.         GetIndString(modelPath, kUSBModelPathString, i);
  574.     }
  575.  
  576.     return numberOfPrinters;
  577. }
  578.  
  579. /*-----------------------------------------------------------------------------*
  580.  
  581.     AddPrintertoList
  582.     
  583.     Desc:        Adds an USB printer to the Chooser's printer list by extracting
  584.                 the name from the name registry
  585.  
  586.     In:            - A printer entry in the name registry
  587.                 - A ptr to user data. This should be a ptr to a 
  588.                   AddPrintertoListCallBackStruct 
  589.                 
  590.     Out:        The number of USB printers in the name registry
  591.     
  592.     History:
  593.     
  594.     24 Feb 98    gp        Created
  595.     
  596.  *-----------------------------------------------------------------------------*/
  597. void    AddPrintertoList( RegEntryID* aPrinterEntry, void* userData )
  598. {
  599.     OSStatus        err = noErr;        // error from name registry call
  600.     Str255            nodeName;            // the name of the printer
  601.     RegPropertyValueSize    nameSize;    // size of name buffer
  602.     AddPrintertoListCallBackStructPtr     fillListStruct=(AddPrintertoListCallBackStructPtr) userData;
  603.     USBGlobalsHandle    gGlobals=nil;    // our global data area
  604.  
  605.     gGlobals = GetGlobalStorage();
  606.  
  607.     nameSize = sizeof( nodeName );
  608.     // grab name of printer in name registyr
  609.     err = SafeRegistryPropertyGet( aPrinterEntry, "name", &nodeName, &nameSize );
  610.     
  611.     if( err == noErr ) {
  612.         // stick it in the printer list
  613.         LAddRow(1, fillListStruct->insertcell.v, fillListStruct->list);
  614.         LSetCell( nodeName, nameSize-1, fillListStruct->insertcell, fillListStruct->list );
  615.         
  616.         // save info about which model (STR#) this printer belongs to
  617.         *((**gGlobals).modelIndex+fillListStruct->insertcell.v) = fillListStruct->modelIndex;
  618.         fillListStruct->insertcell.v++;
  619.     }
  620. }
  621.  
  622. /*-----------------------------------------------------------------------------*
  623.  
  624.     FillUSBList
  625.     
  626.     Desc:        Fills the printer list with the number of USB printers
  627.  
  628.     In:            - The Chooser's printer list handle
  629.                 
  630.     Out:        None
  631.     
  632.     History:
  633.     
  634.     24 Feb 98    gp        Created
  635.     
  636.  *-----------------------------------------------------------------------------*/
  637. void    FillPrinterList( ListHandle list )
  638. {
  639.     AddPrintertoListCallBackStruct    userData;    // struct needed by callback routine
  640.     AddPorttoListCallBackStruct        userPortData;    // struct needed by callback routine
  641.     Str255        modelPath;                        // pstring path in a supported printer model
  642.     short        i;                                // counter
  643.  
  644.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  645.     
  646.     gGlobals = GetGlobalStorage();
  647.     
  648.     userPortData.insertcell.v = 0;
  649.     // if we support serial ports then list serial ports
  650.     if( (**gGlobals).supportsSerial == true ) {
  651.         userPortData.list = list;
  652.         userPortData.insertcell.h = 0;
  653.  
  654.         // add the serial ports to the chooser list
  655.         SearchForSerialPorts( (FoundSerialPortProcPtr) &AddPorttoList, (void*) &userPortData );
  656.     }
  657.  
  658.     // if we support USB then list USB printers
  659.     if( (**gGlobals).supportsUSB == true ) {
  660.         userData.list = list;
  661.         userData.insertcell.v = userPortData.insertcell.v;
  662.         userData.insertcell.h = 0;
  663.  
  664.         i=1;
  665.         // read a supported printer's name registry model path
  666.         GetIndString(modelPath, kUSBModelPathString, i);
  667.         while( (char*) modelPath[0] != 0 )        // if len is zero then no more models
  668.         {
  669.             userData.modelIndex = i;
  670.             // add the USB printers to the chooser list
  671.             SearchForUSBPrinters( modelPath, (FoundUSBPrinterProcPtr) &AddPrintertoList, (void*) &userData );
  672.             i++;
  673.             // read another supported printer's name registry model path
  674.             GetIndString(modelPath, kUSBModelPathString, i);
  675.         }
  676.     }
  677. }
  678.  
  679. /*-----------------------------------------------------------------------------*
  680.     
  681.     ShowSelection
  682.     
  683.     Desc:        Hilites the currently selected printer in the printer list
  684.  
  685.     In:            - Handle to Mac List Mgr list
  686.                 - Name of zone we are currently in
  687.                 
  688.     Out:        OS error if any
  689.     
  690.     History:
  691.     
  692.     21 Apr 98    gp        If only 1 USB printer is listed and no previous selection
  693.                         then select it. If previously selected printer is not available
  694.                         display an alert.
  695.     9  Apr 98    gp        Use hlock not hunlock. Moved foundcell outside loop
  696.     21 Mar 98    gp        Extract previously selected printer from our rsrc
  697.     24 Feb 98    gp        Created
  698.     
  699.  *-----------------------------------------------------------------------------*/
  700. OSErr    ShowSelection (ListHandle list, StringPtr zoneName)
  701. {
  702.     Cell            cell;                            // used to iterate thru printer list, shows selected cell
  703.     Str255            nameBuffer;                        // selected AT printer is on the net, search for the cell
  704.     Boolean            foundCell = false;                // found a cell with same name as selected printer
  705.     Handle            selectedPrinter;                // name of the selected printer
  706.  
  707.     Str255            modelString;                    // path in name registry of printer model
  708.     Handle            printerString;                    // the full path in name registry of selected USB printer
  709.     RegEntryID        thePrinterEntry;                // the node of the USB printer node selected
  710.     OSStatus        err             = noErr;        // err encountered when calling name registry API
  711.     short            hiliteState = kUnHilited;        // hilite state of the button
  712.     USBGlobalsHandle    gGlobals=nil;                // our global data area
  713.     short            connectionType;                    // what type of printer connection, serial or USB
  714.     
  715.     gGlobals = GetGlobalStorage();
  716.  
  717.     // get the current selected printer out of the rsrc
  718.     printerString = GetLastSelectedUSBPrinter();
  719.     if( printerString == nil ) {
  720.         return noErr;
  721.     }
  722.  
  723.     // extract printer name for use later
  724.     selectedPrinter = (Handle) Get1Resource( 'STR ', kPrinterNameString );
  725.     if(  selectedPrinter == nil)
  726.         return noErr;
  727.     HLock( selectedPrinter );
  728.  
  729.     connectionType = GetConnectionType();
  730.     switch( connectionType ) {
  731.         case kSerial:
  732.             SetPt (&cell, 0, 0);
  733.  
  734.             // look for the port
  735.             while ( (!foundCell) && (cell.v < (*list)->dataBounds.bottom) )
  736.             {
  737.                 GetNameFromCell(nameBuffer, cell, list);
  738.  
  739.                 // if it equals the name of the current cell, we found the printer
  740.                 if ( EqualString( (StringPtr) *selectedPrinter, nameBuffer, true, true) ) {
  741.                     foundCell = true;
  742.                 } else
  743.                     cell.v++;
  744.             }
  745.             if( !foundCell )
  746.                 StopAlert(kPrinterNotAvailable, nil);
  747.             break;
  748.         case kUSB:
  749.             HLock( printerString );
  750.  
  751.             // name registry only deals with c strings
  752.             p2cstr( (StringPtr) *printerString );
  753.  
  754.             // check to make sure printer is still in name registry before selecting
  755.             SafeRegistryEntryIDInit(&thePrinterEntry);
  756.             err = SafeRegistryCStrEntryLookup( nil, (char*) *printerString, &thePrinterEntry );
  757.             
  758.             // clean up
  759.             c2pstr( (char*) *printerString );
  760.             HUnlock( printerString );
  761.             SafeRegistryEntryIDDispose( &thePrinterEntry );
  762.  
  763.             // if printer is no longer connected put up an alert
  764.             if( err ) {
  765.                 StopAlert(kPrinterNotAvailable, nil);
  766.             } else {
  767.                 // since user could have connected or disconnect other printers from USB bus
  768.                 // we need to find the exact place in the list and hilite it
  769.  
  770.                 SetPt (&cell, 0, 0);
  771.  
  772.                 // loop through all the printers in the list seeing if there is a
  773.                 // match for the driver's selected printer
  774.                 while ( (!foundCell) && (cell.v < (*list)->dataBounds.bottom) )
  775.                 {
  776.                     GetNameFromCell(nameBuffer, cell, list);
  777.  
  778.                     // If the name is one of our reserved rows and
  779.                     // it equals the name of the current cell, we found a possible printer
  780.                     
  781.                     if ( EqualString( (StringPtr) *selectedPrinter, nameBuffer, true, true) ) {
  782.  
  783.                         // create name registry full path for this printer and compare it
  784.                         // to the one thats stored in our rsrc
  785.                         
  786.                         // get the printers model
  787.                         GetIndString(modelString, kUSBModelPathString, *((**gGlobals).modelIndex+cell.v) );
  788.                         if( modelString[0] != 0 ) 
  789.                         {
  790.                             // create the path
  791.                             AppendPStr( (StringPtr) modelString, "\p:" );
  792.                             AppendPStr( (StringPtr) modelString, nameBuffer );
  793.                             // check to see if its the same
  794.                             HLock( printerString );
  795.                             if ( EqualString( modelString, (StringPtr) *printerString, true, true) )
  796.                                 foundCell = true;
  797.                             HUnlock( printerString );
  798.                         }
  799.                     }
  800.  
  801.                     if (!foundCell)
  802.                         cell.v++;
  803.                 } // end while
  804.             } // end else
  805.             break;
  806.         default:
  807.             break;
  808.     }
  809.     HUnlock( selectedPrinter );
  810.  
  811.     // if this is our first time and only 1 entry in the list and its USB then select it
  812.     if( ((**gGlobals).supportsUSB == true) && !foundCell && 
  813.         ((*list)->dataBounds.bottom == 1) && ((**gGlobals).numberOfUSBPrinters == 1) ) 
  814.     {
  815.         if( printerString != nil && (**printerString) == 0x0) {
  816.             SetPt(&cell, 0, 0);        // select the 1st cell
  817.  
  818.             if( SaveSelectedUSBPrinter( cell, list ) ) {
  819.                 // save the name of the printer
  820.                 SaveSelectedPrinterName( cell, list );
  821.                 foundCell = true;
  822.             }
  823.         }
  824.     }
  825.  
  826.     // now hilite the selection
  827.     if (foundCell)
  828.     {
  829.         LSetSelect(true, cell, list);
  830.         hiliteState = kHilited;
  831.     }
  832.  
  833.  
  834.     return noErr;
  835. }
  836.  
  837. /*-----------------------------------------------------------------------------*
  838.  
  839.     Select
  840.     
  841.     Desc:        Save the selected printers name and name registry path in our rsrc
  842.  
  843.     In:            - Handle to Mac List Mgr list
  844.                 - Name of zone we are currently in
  845.                 - the row Chooser thinks we should select.
  846.                 
  847.     Out:        OS error if any
  848.     
  849.     History:
  850.     
  851.     21 Mar 98    gp        Save printer name in our rsrc
  852.     24 Feb 98    gp        Created
  853.  
  854. *-----------------------------------------------------------------------------*/
  855. OSErr    Select (ListHandle list, StringPtr zoneName, long rowNum)
  856. {
  857.     
  858.     Str255            modelString;            // path in name registry of printer model
  859.     Handle            printerString=nil;        // path in name registry of current USB printer
  860.     Cell            selectedCell;            // for list processing
  861.     Str32            selectedPrinterName;    // select printer in list
  862.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  863.  
  864.     gGlobals = GetGlobalStorage();
  865.  
  866.     // Find out which row was selected
  867.     SetPt (&selectedCell, 0, 0);
  868.     LGetSelect (true, &selectedCell, list);
  869.  
  870.     // Get the name of the printer that was selected out of the list
  871.     GetNameFromCell (selectedPrinterName, selectedCell, list);
  872.  
  873.     // if nothing selected leave
  874.     if( selectedPrinterName[0] == 0 )
  875.         return noErr;
  876.  
  877.     // serial port selected so just clear the USB model path in the STR rsrc
  878.     if( selectedCell.v < (**gGlobals).numberOfPorts ) {
  879.         printerString = GetLastSelectedUSBPrinter();
  880.         (**printerString) = 0;
  881.         ChangedResource( printerString );
  882.         SetConnectionType( kSerial );
  883.         WriteResource(printerString);
  884.     } else {
  885.         SaveSelectedUSBPrinter( selectedCell, list );
  886.     }
  887.  
  888.     // save the name of the printer
  889.     SaveSelectedPrinterName( selectedCell, list );
  890.     return noErr;
  891. }
  892.  
  893. /*-----------------------------------------------------------------------------*
  894.  
  895.     InitPack
  896.     
  897.     Desc:        Creates our global storage and reads info out of our
  898.                 connection info rsrc
  899.  
  900.     In:            None
  901.  
  902.     Out:        OS error if any
  903.     
  904.     History:
  905.     
  906.     8  May 98    gp        If we don't support USB then no need to init the name registry
  907.                         ptrs. This will prevent the name registry alert from
  908.                         displaying on non PCI PowerMacs if we only support serial.
  909.     8  May 98    gp        Moved creation of model index to here from InitGlobalStorage
  910.     21 Apr 98    gp        If we don't support serial set numberOfPorts to zero
  911.     27 Mar 98    gp        Created
  912.  
  913.  *-----------------------------------------------------------------------------*/
  914. OSErr    InitPack(void)
  915. {
  916.     OSErr                returnValue            = noErr;    // return value
  917.     USBGlobalsHandle    gGlobals            = nil;        // our global data area
  918.     ConnectionTypeHdl    connectionInfo        = nil;
  919.     short                numberOfUSBPrinters = 0;        // number of USB printers detected
  920.     short                numberOfPorts        = 0;        // number of serial ports
  921.  
  922.     // initialize our global storage
  923.     returnValue = InitGlobalStorage();
  924.     if( returnValue == noErr ) 
  925.     {
  926.         gGlobals = GetGlobalStorage();
  927.         connectionInfo = (ConnectionTypeHdl) Get1Resource( kConnectionType, kConnectionTypeID );
  928.         if( connectionInfo != nil )
  929.         {
  930.             (**gGlobals).supportsSerial = ( (**connectionInfo).supportsSerial == 1 );
  931.             (**gGlobals).supportsUSB = ( (**connectionInfo).supportsUSB == 1 );
  932.  
  933.             // if we don't support serial ports then zero out serial port count
  934.             if( (**gGlobals).supportsSerial == false )
  935.                 (**gGlobals).numberOfPorts = 0;
  936.         }
  937.         
  938.         // count USB printers
  939.         if( (**gGlobals).supportsUSB == true )
  940.         {
  941.             // if we support USB we need to init proc ptrs before calling CountUSBPrinters
  942.             InitNameRegistryPtrs();
  943.  
  944.             numberOfUSBPrinters = CountUSBPrinters();
  945.             (**gGlobals).numberOfUSBPrinters = numberOfUSBPrinters;
  946.         } else {
  947.             numberOfUSBPrinters = 0;
  948.             (**gGlobals).numberOfUSBPrinters = 0;
  949.         }
  950.  
  951.         // count serial ports
  952.         if( (**gGlobals).supportsSerial == true ) {
  953.             numberOfPorts = CountSerialPorts();
  954.             (**gGlobals).numberOfPorts = numberOfPorts;
  955.         } else {
  956.             numberOfPorts = 0;
  957.             (**gGlobals).numberOfPorts = 0;
  958.         }
  959.  
  960.         // allocate our index storage
  961.         // there is index space for serial ports which are unused but make the code simpler
  962.         (**gGlobals).modelIndex = (short*) NewPtr( (numberOfPorts+numberOfUSBPrinters)*sizeof(short) );
  963.         if ( (**gGlobals).modelIndex == nil )
  964.         {
  965.             // no index storage so get rid of our globals too
  966.             RemoveGlobalStorage();
  967.             returnValue = memFullErr;
  968.         }
  969.  
  970.     }
  971.     return returnValue;
  972. }
  973.  
  974. /*-----------------------------------------------------------------------------*
  975.  
  976.     Chooser
  977.     
  978.     Desc:        Routines to handle calls from the Chooser
  979.  
  980.     In:            - message from chooser
  981.                 - application id
  982.                 - additional info (varies)
  983.                 - name of the appletalk zone
  984.                 - handle to device choices ( printers )
  985.                 - additional info (varies)
  986.  
  987.     Out:        OS error if any
  988.     
  989.     History:
  990.     
  991.     19 Mar 98    gp        Created
  992.  
  993.  *-----------------------------------------------------------------------------*/
  994. pascal    OSErr    Chooser (short message, short caller, StringPtr objName, StringPtr zoneName, long p1, long p2)
  995. {
  996.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  997.     OSErr returnValue = noErr;                // return value
  998.  
  999.     gGlobals = GetGlobalStorage();
  1000.     switch (message)
  1001.     {
  1002.         case chooserInitMsg:
  1003.             returnValue = InitPack();
  1004.             break;
  1005.         case fillListMsg:
  1006.             if( gGlobals != nil )
  1007.                 FillPrinterList( (ListHandle) p1 );
  1008.             break;
  1009.         case getSelMsg:
  1010.             if( gGlobals != nil )
  1011.                 ShowSelection ( (ListHandle)p1, zoneName);
  1012.             break;
  1013.         case selectMsg:
  1014.             if( gGlobals != nil )
  1015.                 Select ( (ListHandle)p1, zoneName, p2);
  1016.             break;
  1017.         case buttonMsg:
  1018.             break;
  1019.         case terminateMsg:
  1020.             RemoveNameRegistryPtrs();
  1021.             RemoveGlobalStorage();
  1022.             break;
  1023.         case deselectMsg:
  1024.             break;
  1025.         default:
  1026.             break;
  1027.     }
  1028.     return returnValue;
  1029. }
  1030.  
  1031. /*-----------------------------------------------------------------------------*
  1032.  
  1033.     InitGlobalStorage
  1034.     
  1035.     Desc:        Creates and stores a block of memory in our rsrc to be
  1036.                 used as global storage
  1037.  
  1038.     In:            none
  1039.  
  1040.     Out:        OS error if any
  1041.     
  1042.     History:
  1043.     
  1044.     10 Jun 98    gp        Lock our global area
  1045.     9  Jun 98    gp        Clear the handle when creating the global storage
  1046.                         Remove old global rsrc if its still there
  1047.     8  May 98    gp        Moved creation of model index to InitPack
  1048.     25 Mar 98    gp        Created
  1049.  
  1050.  *-----------------------------------------------------------------------------*/
  1051. OSErr    InitGlobalStorage(void)
  1052. {
  1053.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  1054.     Handle    globalrsrc;                        // handle to store our global data address
  1055.  
  1056.     // get rid of old global rsrc if its still there
  1057.     globalrsrc = (Handle) Get1Resource(kGlobalType, kGlobalID);
  1058.     if( globalrsrc != nil ) {
  1059.         RemoveResource( globalrsrc );
  1060.         DisposeHandle( globalrsrc );
  1061.     }
  1062.  
  1063.     // allocate our global storage
  1064.     gGlobals = (USBGlobalsHandle) NewHandleClear( sizeof( USBGlobals ) );
  1065.     globalrsrc = NewHandleClear( sizeof( Handle ) );
  1066.     if (gGlobals != nil) 
  1067.     {
  1068.         HLockHi( (Handle) gGlobals );
  1069.         // save our global handle address in our rsrc
  1070.         (** (Handle**) globalrsrc) = (char**) gGlobals;
  1071.         addresource( globalrsrc, kGlobalType, kGlobalID,(char*) "\p");
  1072.  
  1073.         return noErr;
  1074.     } else
  1075.         return memFullErr;
  1076. }
  1077.  
  1078. /*-----------------------------------------------------------------------------*
  1079.  
  1080.     GetGlobalStorage
  1081.     
  1082.     Desc:        Retrieves our global stoarge area
  1083.  
  1084.     In:            none
  1085.  
  1086.     Out:        Handle to our global storage
  1087.     
  1088.     History:
  1089.     
  1090.     25 Mar 98    gp        Created
  1091.  
  1092.  *-----------------------------------------------------------------------------*/
  1093. USBGlobalsHandle    GetGlobalStorage(void)
  1094. {
  1095.     Handle    ourRsrc=nil;                    // handle to ourselves
  1096.  
  1097.     ourRsrc = (Handle) Get1Resource(kGlobalType, kGlobalID);
  1098.     if( ourRsrc == nil )
  1099.         return nil;
  1100.     
  1101.     return (**(USBGlobalsHandle**)ourRsrc);
  1102. }
  1103.  
  1104. /*-----------------------------------------------------------------------------*
  1105.  
  1106.     RemoveGlobalStorage
  1107.     
  1108.     Desc:        Removes our global storage area
  1109.  
  1110.     In:            none
  1111.  
  1112.     Out:        Handle to our global storage
  1113.     
  1114.     History:
  1115.     
  1116.     9  Jun 98    gp        Dispose of our global rsrc after removing it
  1117.     26 Mar 98    gp        Release model index storage
  1118.     25 Mar 98    gp        Created
  1119.  
  1120.  *-----------------------------------------------------------------------------*/
  1121. void    RemoveGlobalStorage(void)
  1122. {
  1123.     USBGlobalsHandle    gGlobals=nil;        // our global data area
  1124.     Handle                ourRsrc;
  1125.     
  1126.     gGlobals = GetGlobalStorage();
  1127.     if( gGlobals != nil ) {
  1128.         // dispose of index ptr
  1129.         
  1130.         if ( (**gGlobals).modelIndex != nil )
  1131.         {
  1132.             DisposePtr( (Ptr) (**gGlobals).modelIndex );
  1133.         }
  1134.              
  1135.         // remove our global handle
  1136.         HUnlock( (Handle) gGlobals );
  1137.         DisposeHandle( (Handle) gGlobals );
  1138.         // remove our rsrc for global address storage
  1139.         ourRsrc = (Handle) Get1Resource(kGlobalType, kGlobalID);
  1140.         RemoveResource( ourRsrc );
  1141.         DisposeHandle( ourRsrc );
  1142.     }
  1143. }
  1144. // eof
  1145.